package com.boot.netty.handler;

import com.boot.netty.NettyHttpProxyApplication;
import com.boot.netty.cache.ChannelCache;
import com.boot.netty.utils.ChannelUtils;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.HttpHeaderNames;
import lombok.extern.slf4j.Slf4j;

import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class NettyProxyServerHandler extends ChannelInboundHandlerAdapter {

    private final static String AUTHORIZATION = "Authorization: Basic ";

    private Map<Channel, Channel> channelMap = new ChannelCache();

    private Map<Channel, ByteBuf> msgMap = new HashMap<>();//之所以保留这个map是担心，第一次建立连接时一次性无法获取客户端发来的全部信息

    public NettyProxyServerHandler() {
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        if (channelMap.containsKey(ctx.channel())) {
            channelMap.remove(ctx.channel());
        }
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        Channel channel = ctx.channel();
        if (channelMap.containsKey(channel)) {
            channelMap.get(channel).writeAndFlush(msg);
        } else {
            ByteBuf buffer = msgMap.containsKey(channel) ? msgMap.get(channel) : ctx.alloc().buffer(1024 * 2);
            buffer.writeBytes((ByteBuf) msg);
            buffer.retain();
            msgMap.put(channel, buffer);
        }
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        //如果是还没建立连接，需要对目标host和port进行解析
        if (!channelMap.containsKey(channel)) {
            if (msgMap.containsKey(channel)) {
                ByteBuf byteBuf = msgMap.get(channel);
                byte[] bytes = new byte[byteBuf.readableBytes()];
                byteBuf.getBytes(0, bytes);
                String header = new String(bytes);
                String[] split = header.split("\\n");
                String host = "";
                int port = 80;
                int type = 0;                   //默认是http方式
                String hostTemp = "";
                for (int index = 0; index < split.length; index++) {
                    String indexStr = split[index];
                    if (indexStr.contains(AUTHORIZATION) || AuthorizationHandler.needAuthorization()) {
                        String token = indexStr.substring(AUTHORIZATION.length());
                        String decode = new String(Base64.getDecoder().decode(token.replace("\\r","")));
                        if (!AuthorizationHandler.authorization(decode)) {
                            throw new RuntimeException("密码错误");
                        }
                    }

//                    String s = NettyHttpProxyApplication.authenticate(request.headers().get(HttpHeaderNames.PROXY_AUTHORIZATION));
                    if (index == 0) {
                        type = indexStr.split(" ")[0].equalsIgnoreCase("CONNECT") ? 1 : 0;
                    } else {
                        String[] hostLine = indexStr.split(": ");
                        if (hostLine[0].equalsIgnoreCase("host")) {
                            hostTemp = hostLine[1];
                        }
                    }
                }
                if (hostTemp.split(":").length > 1) {
                    host = hostTemp.split(":")[0];
                    port = Integer.valueOf(hostTemp.split(":")[1].split("\\r")[0]);
                } else {
                    host = hostTemp.split(":")[0].split("\\r")[0];
                }

                Channel serverChannel = ChannelUtils.connect(host, port, new ToServerHandler(channelMap));
                channelMap.put(channel, serverChannel);
                channelMap.put(serverChannel, channel);
                if (type == 1) { //https请求处理
                    ByteBuf buffer = channel.alloc().buffer("HTTP/1.1 200 Connection Established\r\n\r\n".getBytes().length);
                    buffer.writeBytes("HTTP/1.1 200 Connection Established\r\n\r\n".getBytes());
                    channel.writeAndFlush(buffer);
                } else {
                    serverChannel.writeAndFlush(msgMap.get(channel));
                }
                msgMap.get(channel).release();
                log.info("{}:{}连接建立成功", host, port);
            } else {
                log.info("=======连接建立失败");
            }
        }

    }
}
